모듈 라이선스 관리
어셈블리 서명: 라이선스 발급을 위해 어셈블리는 서명이 필요하므로, 프로젝트 파일에 다음과 같이 모듈 명과 동일하게 서명 파일을 만들고 설정을 추가합니다. modulename.snk 서명 파일은 프로젝트 루트에 위치해야 합니다.
sn -k modulename.snk
.NET 어셈블리에 서명(Strong-Name Signing)을 하는 주된 이유는 다음과 같습니다.
- 고유한 신원 (Unique Identity) 및 이름 충돌 방지
- 무결성 보장 (Integrity Assurance)
- 신뢰의 원천 (Source of Trust)
- GAC (Global Assembly Cache) 등록 필수
- 버전 관리 및 Side-by-Side 실행
- 보안 정책 (Code Access Security)
<PropertyGroup>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>modulename.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
.snk 파일은 공개 키와 개인 키 쌍을 포함하고 있으며, 어셈블리에 서명하는 데 사용됩니다. 공개 키는 어셈블리의 신원을 확인하는 데 사용되고, 개인 키는 서명을 생성하는 데 사용됩니다.
서명 파일이 유출되면, 누구나 해당 서명자를 사칭하여 어셈블리를 위조하거나 변조할 수 있게 됩니다. .snk 파일이 유출되지 않도록 주의해야 합니다.
주의: .snk 파일은 민감한 정보이므로, 절대 공개 된 관리 시스템(예: Git, Svn)에 커밋하지 마십시오. 대신, 비밀 관리 시스템이나 안전한 위치에 보관하고 필요할 때만 사용하십시오.
만약 .snk 파일을 유출 되거나 분실한 경우, 해당 서명으로 서명된 어셈블리를 더 이상 업데이트할 수 없으므로, 이전 버전에 대한 호환성 업무를 검토하고 대응 계획 수립 후에, 새로운 키 쌍을 생성하고 어셈블리를 다시 서명해야 합니다.
모듈 라이선스 키는 무엇인가?
모듈 라이선스 키는 모듈을 특정 고객사에 독점적으로 사용하도록 허가하는 고유한 키입니다. 이 키는 모듈의 코드와 설정을 암호화하는 데 사용되며, 라이선스 키가 없으면 모듈을 사용할 수 없습니다. 이를 통해 모듈의 무단 복제 및 배포를 방지하고, 개발사의 기술 보호를 강화합니다.
HandStack 에서 제공하는 dbclient, function, transact 모듈의 Contract 코드 및 설정은 모두 모듈 라이선스 키로 암호화되어 배포됩니다. 각 고객사는 고유한 라이선스 키를 발급받아 해당 모듈을 사용할 수 있습니다.
그러나 모듈 라이선스 키는 모듈 소프트웨어의 복제 방지 및 무단 사용을 막기 위한 수단일 뿐, HandStack 플랫폼의 라이선스 정책과는 별개입니다. HandStack 플랫폼은 MIT 라이선스 정책에 따라 오픈 소스로 사용되며, 모듈 라이선스 키는 해당 플랫폼의 사용 권한을 대체하지 않습니다.
모듈 라이선스 키는 서버 측과, 클라이언트 측에서 각각 검증을 위한 코드가 포함되어 있습니다. 서버 측에서는 ack 서버가 모듈을 로드할 때 라이선스 키를 검증하고, 클라이언트 측에서는 업무 화면이 실행될 때 라이선스 키를 검증합니다.
서버 측 라이선스 키 예
{
"Licenses": {
"custom-api-module": {
"CompanyName": "HandStack",
"ProductName": "CustomApiModule-v1.0.0-PROD001",
"AuthorizedHost": "handstack.kr,www.handstack.kr",
"Key": "NDJlNjE2YjE2N2FmMjA3ZmZkN2I0NmQ4ZTFhM2IyZjU6YTUwYTc2ZGQ4MjZhYjZkM2YxNmQwMThkNzA4ODVhYmE2M2NkY2IyZmNkNzg1ZGE0OWUxYzk3MTAwOWMwMTc1N2JmMjBiZWU3M2EzZDFhMTRkNGI4NWM1ZTA2NzBkNmQ0ZWQyMWQ2NjRiMTMxOWQ3OGM1ZWFmYWY3YTUzMjRlNTliNDg5M2FlYjgyMzhjMmY4YTFjMDVmOGIzOGJiZTJjZTc0OTc5ODRiYWQ5YzA3Mjc5OWY5ZTA0ZWFjZTQyM2E4NmE3YWM1YzdiZDg3MmFkMGU4NWY1ZGNlMTBlZmFiMGExNThjZGU2Nzk3OGUzMDNlNDExNWM0MmY2ZGIwMzkzMg==",
"CreatedAt": "2025-08-25T03:22:12.304Z",
"ExpiresAt": "2026-07-01T23:59:59.000Z",
"Environment": "Production",
"SignKey": "ac3263d40c5950c94302f738cf8bd1ef82613b3fb8c9e14a3e456620d3f327cc.handstack-salt-value"
}
},
"GeneratedAt": "2025-08-25T03:22:12.328Z",
"GeneratedBy": "handstack",
"Version": "1.0.0"
}
이 정보는 ack 서버가 시작될 때 appsettings.json 파일에서 읽어들여, 모듈을 로드 할 때 해당 모듈의 라이선스 키를 검증하는 데 사용됩니다.
{
...
"LoadModules": [
"wwwroot",
"transact",
"dbclient",
"function",
"repository",
"logger",
"custom-api-module"
],
"LoadModuleLicenses": {
"custom-api-module": {
"CompanyName": "HandStack",
"ProductName": "CustomApiModule-v1.0.0-PROD001",
"AuthorizedHost": "handstack.kr,www.handstack.kr",
"Key": "NDJlNjE2YjE2N2FmMjA3ZmZkN2I0NmQ4ZTFhM2IyZjU6YTUwYTc2ZGQ4MjZhYjZkM2YxNmQwMThkNzA4ODVhYmE2M2NkY2IyZmNkNzg1ZGE0OWUxYzk3MTAwOWMwMTc1N2JmMjBiZWU3M2EzZDFhMTRkNGI4NWM1ZTA2NzBkNmQ0ZWQyMWQ2NjRiMTMxOWQ3OGM1ZWFmYWY3YTUzMjRlNTliNDg5M2FlYjgyMzhjMmY4YTFjMDVmOGIzOGJiZTJjZTc0OTc5ODRiYWQ5YzA3Mjc5OWY5ZTA0ZWFjZTQyM2E4NmE3YWM1YzdiZDg3MmFkMGU4NWY1ZGNlMTBlZmFiMGExNThjZGU2Nzk3OGUzMDNlNDExNWM0MmY2ZGIwMzkzMg==",
"CreatedAt": "2025-08-25T03:22:12.304Z",
"ExpiresAt": "2026-07-01T23:59:59.000Z",
"Environment": "Production",
"SignKey": "ac3263d40c5950c94302f738cf8bd1ef82613b3fb8c9e14a3e456620d3f327cc.handstack-salt-value"
}
}
...
}
클라이언트 측 라이선스 키 예 (customApiModuleLicense.js)
/*!
* Product ID: CustomApiModule-v1.0.0-PROD001
* Authorized Domain(or IP): handstack.kr,www.handstack.kr
* Publisher: handstack.kr
* Generated: 2025-08-25 03:22:12 UTC
* Generated By: handstack
* Module ID: custom-api-module
* Environment: Production
* Expires: 2026-07-01T23:59:59.000Z
*/
/* eslint-disable */
var customApiModuleLicense = "NDJlNjE2YjE2N2FmMjA3ZmZkN2I0NmQ4ZTFhM2IyZjU6YTUwYTc2ZGQ4MjZhYjZkM2YxNmQwMThkNzA4ODVhYmE2M2NkY2IyZmNkNzg1ZGE0OWUxYzk3MTAwOWMwMTc1N2JmMjBiZWU3M2EzZDFhMTRkNGI4NWM1ZTA2NzBkNmQ0ZWQyMWQ2NjRiMTMxOWQ3OGM1ZWFmYWY3YTUzMjRlNTliNDg5M2FlYjgyMzhjMmY4YTFjMDVmOGIzOGJiZTJjZTc0OTc5ODRiYWQ5YzA3Mjc5OWY5ZTA0ZWFjZTQyM2E4NmE3YWM1YzdiZDg3MmFkMGU4NWY1ZGNlMTBlZmFiMGExNThjZGU2Nzk3OGUzMDNlNDExNWM0MmY2ZGIwMzkzMg==.ac3263d40c5950c94302f738cf8bd1ef82613b3fb8c9e14a3e456620d3f327cc.handstack-salt-value";
if (typeof window !== "undefined") window.customApiModuleLicense = customApiModuleLicense;
이 정보는 클라이언트 측에서 업무 화면이 실행될 때 라이선스 키를 검증하는 데 사용됩니다.
모듈 라이선스 키 발급 하기
HandStack 2025.8.25 버전부터는 고객사별로 고유한 모듈 라이선스 키를 발급하여, 모듈의 코드 및 설정을 암호화하는 방식을 도입하였습니다. 이를 통해 모듈의 무단 복제 및 배포를 방지하고, 개발사의 기술 보호를 강화합니다.
handstack CLI 도구로 공개 키 확인
모듈 소프트웨어의 공개 키는 HandStack handstack/4.Tool/CLI/handstack 디렉토리에 있는 handstack CLI 도구를 사용하여 확인 할 수 있습니다. 이 도구는 .NET 환경에서 실행되며, 다음과 같은 명령어로 사용할 수 있습니다.
handstack publickey --file="C:\projects\company\modules\modulename\bin\Debug\net10.0\modulename.dll"
어셈블리 파일 경로: C:\projects\company\modules\modulename\bin\Debug\net10.0\modulename.dll
어셈블리 이름: modulename
어셈블리 버전: 1.0.0.0
강력한 이름 서명: 예
공개 키 (Hex):
00240000048000009400000006020000002400005253413100040000010001002D5CE5F5F32A43756616EB6619AF8F15FCB8ABA785AA38919E919617C93B2048254D3CBED2F27D1C91AA0876758766A9DE6A357853883ACA677A0AC7399C8466C5345E4F68228BDA5380B974451ACE1413B8CC7E22778E69FBBE6A609169A3E9EF798EB6C21B37C793F8A66C361F43ABDE0BD27171EC59F14574D39D40EB01B7
공개 키 (Base64):
ACQAAASAAACUAAAABgIAAAAkAABSU0ExAAQAAAEAAQAtXOX18ypDdWYW62YZr48V/Lirp4WqOJGekZYXyTsgSCVNPL7S8n0ckaoIdnWHZqneajV4U4g6ymd6Csc5nIRmxTReT2gii9pTgLl0RRrOFBO4zH4id45p+75qYJFpo+nveY62whs3x5P4pmw2H0Or3gvScXHsWfFFdNOdQOsBtw==
공개 키 (SHA256):
e066b046f40c9f1fd0c263265227be9e068a73be1f403e482f484fbc450148b9
공개 키 (Token):
b9af6de54c4bdeb3
지적 재산권 보호를 위한 개발사 정보를 변경
텍스트 편집기로 handstack/4.Tool/CLI/node-cli/license-cli/license-manager.js 파일을 열고, 다음과 같은 기본 설정 값을 개발사에 맞게 변경합니다.
this.saltValue = 'handstack-salt-value';
this.publisher = 'handstack.kr';
this.allowedDomains = ['localhost', '127.0.0.1'];
this.currentUser = 'handstack';
- saltValue: 라이선스 키 생성 및 검증에 사용되는 솔트 값입니다. 개발사의 모듈 소프트웨어의 공개 키을 설정합니다. (예: e066b046f40c9f1fd0c263265227be9e068a73be1f403e482f484fbc450148b9)
- publisher: 라이선스 키에 포함될 발행자 정보입니다. 개발사의 도메인이나 이름을 설정합니다.
- allowedDomains: 라이선스 키에 포함될 허용된 도메인 목록입니다. 개발사의 도메인이나 IP 주소를 설정합니다.
- currentUser: 라이선스 키 생성 시 기록될 사용자 정보입니다. 개발사의 이름이나 ID를 설정합니다.
license-cli.js 도구 사용
모듈 라이선스 키는 HandStack handstack/4.Tool/CLI/node-cli/license-cli 디렉토리에 있는 license-cli.js CLI 도구를 사용하여 발급할 수 있습니다. 이 도구는 Node.js 환경에서 실행되며, 다음과 같은 명령어로 사용할 수 있습니다.
cd handstack/4.Tool/CLI/node-cli/license-cli
npm install
node license-cli.js create --module-id "custom-api-module" --company "HandStack" --product "CustomApiModule-v1.0.0-PROD001" --hosts "handstack.kr,www.handstack.kr" --environment "Production" --expires "2026-07-01T23:59:59.000Z" --gen-js --js-dir "./generated-licenses"
node license-cli.js create --module-id "custom-api-module" --company "HandStack" --product "CustomApiModule-v1.0.0-PROD001" --hosts "handstack.kr,www.handstack.kr" --environment "Production" --expires "2026-07-01T23:59:59.000Z" --gen-js --js-dir "./generated-licenses"
위의 명령을 실행하면, 지정한 모듈 ID, 회사명, 제품명, 허용된 호스트, 환경, 만료일 등을 기반으로 모듈 라이선스 키가 생성됩니다. --gen-js 옵션을 사용하면 클라이언트 측에서 사용할 수 있는 JavaScript 파일도 generated-licenses 디렉토리에 함께 생성됩니다.
여기에서 개발사에 맞게 어셈블리 서명을 하여 [모듈 소프트웨어 공개 키]를 포함해서 개발사의 지적 재산권 보호를 위한 추가 정보를 변경 해야 합니다. 이 공개 키는 모듈 소프트웨어의 무결성을 검증하는 데 사용됩니다.
모듈 라이선스 키로 dbclient, function, transact 모듈 Contract 코드 및 설정 암호화 하기
외부로 배포되는 모듈 애플리케이션을 개발할 때는 주요 코드 (C#, JavaScript) 에 대해 난독화 도구를 사용하는 것을 검토하는 권장합니다. 또한, 모듈 라이선스 키로 Contract 코드 및 설정을 암호화하여, 무단 복제 및 배포를 방지하고, 개발사의 기술 보호를 강화할 수 있습니다.
모듈 라이선스 키로 dbclient, function, transact 모듈의 Contract 코드 및 설정을 암호화하려면 HandStack handstack/4.Tool/CLI/handstack 디렉토리에 있는 handstack CLI 도구를 사용하여 확인 할 수 있습니다. 이 도구는 .NET 환경에서 실행되며, 다음과 같은 명령어로 사용할 수 있습니다.
handstack encryptcontracts --file="C:\projects\company\modules\modulename\bin\Debug\net10.0\modulename.dll" --directory="C:\projects\company\modules\modulename\bin\Debug\net10.0\Contracts"
위의 명령을 실행하면, 지정한 모듈 어셈블리 파일 경로와 Contract 디렉토리를 기반으로 Contract 코드 및 설정이 암호화됩니다. 이때, 모듈 어셈블리 파일에 포함된 공개 키와 토큰 키를 사용하여 암호화가 수행됩니다.